﻿#include "http_srv.h"

#include <fstream>

#define API_URI_HEADER "/api"

//////////////////////////////////////////////////////////////////////////
std::shared_ptr<json_rep> value_from_json(std::string& v, const std::string& name,
                                          json::object& jo) {
    auto jv = jo.if_contains(name);
    if (!jv)
        return std::make_shared<json_rep>(HTTP_FIELD_NOT_FOUND(name));   // 属性未找到

    if (!jv->is_string())
        return std::make_shared<json_rep>(HTTP_FIELD_TYPE_ERR(name, "string"));

    v = jv->as_string();
    return nullptr;
}

std::shared_ptr<json_rep> value_from_json(int& v, const std::string& name, json::object& jo) {
    auto jv = jo.if_contains(name);
    if (!jv)
        return std::make_shared<json_rep>(HTTP_FIELD_NOT_FOUND(name));   // 属性未找到

    if (!jv->is_int64())
        return std::make_shared<json_rep>(HTTP_FIELD_TYPE_ERR(name, "int"));
    v = (int)jv->as_int64();
    return nullptr;
}

std::shared_ptr<json_rep> value_from_json(uint64_t& v, const std::string& name, json::object& jo) {
    auto jv = jo.if_contains(name);
    if (!jv)
        return std::make_shared<json_rep>(HTTP_FIELD_NOT_FOUND(name));   // 属性未找到
    if (!jv->is_int64())
        return std::make_shared<json_rep>(HTTP_FIELD_TYPE_ERR(name, "uint"));
    v = jv->as_uint64();
    return nullptr;
}

std::shared_ptr<json_rep> value_from_json(bool& v, const std::string& name, json::object& jo) {
    auto jv = jo.if_contains(name);
    if (!jv)
        return std::make_shared<json_rep>(HTTP_FIELD_NOT_FOUND(name));   // 属性未找到
    if (!jv->is_int64())
        return std::make_shared<json_rep>(HTTP_FIELD_TYPE_ERR(name, "bool"));
    v = jv->as_bool();
    return nullptr;
}

std::shared_ptr<json_rep> value_from_json(double& v, const std::string& name, json::object& jo) {
    auto jv = jo.if_contains(name);
    if (!jv)
        return std::make_shared<json_rep>(HTTP_FIELD_NOT_FOUND(name));   // 属性未找到
    if (!jv->is_double())
        return std::make_shared<json_rep>(HTTP_FIELD_TYPE_ERR(name, "double"));
    v = jv->as_double();
    return nullptr;
}

std::shared_ptr<json_rep> value_from_json(json::object& v, const std::string& name,
                                          json::object& jo) {
    auto jv = jo.if_contains(name);
    if (!jv)
        return std::make_shared<json_rep>(HTTP_FIELD_NOT_FOUND(name));   // 属性未找到
    if (!jv->is_object())
        return std::make_shared<json_rep>(HTTP_FIELD_TYPE_ERR(name, "object"));
    v = jv->as_object();
    return nullptr;
}

//////////////////////////////////////////////////////////////////////////
// class http_srv
http_srv::http_srv()
    : m_http_router(nullptr)
    , m_ws_router(nullptr)
    , m_http_server(nullptr) {
    // 禁用libhv的日志
    hlog_disable();
}

http_srv::~http_srv() {
    if (m_http_server)
        stop();
}

int http_srv::start(unsigned short port) {
    if (m_http_server)
        stop();

    // HTTP 路由
    m_http_router = std::make_shared<HttpService>();
    m_http_router->AllowCORS();
    // 注册默认的 远程调用（API） 服务
    m_http_router->Any(API_URI_HEADER, [this](HttpRequest* req, HttpResponse* resp) {
        return http_handler(req, resp);
    });

    // websocket 路由
    m_ws_router = std::make_shared<WebSocketService>();
    // 注册默认的 websocket 消息处理
    m_ws_router->onopen =
        std::bind(&http_srv::ws_open, this, std::placeholders::_1, std::placeholders::_2);
    m_ws_router->onmessage =
        std::bind(&http_srv::ws_message, this, std::placeholders::_1, std::placeholders::_2);
    m_ws_router->onclose = std::bind(&http_srv::ws_close, this, std::placeholders::_1);

    // 启动 HTTP 服务
    m_http_server          = std::make_shared<http_server_t>();
    m_http_server->port    = port;
    m_http_server->service = m_http_router.get();
    m_http_server->ws      = m_ws_router.get();
    int ret                = http_server_run(m_http_server.get(), 0);
    on_start(port, ret);   // 发送消息：服务启动

    return ret;
}

void http_srv::stop() {
    if (m_http_server) {
        http_server_stop(m_http_server.get());
        on_stop();   // 发送消息：服务停止
    }

    m_http_server.reset();
    m_http_router.reset();
    m_ws_router.reset();
}

int http_srv::http_handler(HttpRequest* req, HttpResponse* resp) {
    std::string        method   = req->Method();
    std::string        uri      = req->Path();
    const std::string& req_body = req->Body();

    on_request(method, req->Url());   // 发送消息：收到新的 HTTP Request

    // 根据 URI 分派和处理请求
    json_rep result;
    try {
        std::string api_path = make_path(method, uri);
        if (m_map_funcs.find(api_path) != m_map_funcs.end()) {   // 根据 method + uri
            // 查找远程调用
            auto f = m_map_funcs[api_path];

            // 找到的处理函数，如果参数定义不为空，则body中的数据必须是 JSON Object
            json::value v;
            if (f.params_def.size() > 0) {
                json::error_code ec;

                boost::json::parse_options opt;
                opt.allow_comments        = true;
                opt.allow_trailing_commas = true;
                opt.allow_invalid_utf8    = true;

                v = json::parse(req_body, ec, {}, opt);   // 请求内容 -> JSON
                if (ec && req->query_params.size() <= 0)   // body 不是 JSON，且没有 query，报错
                    HTTP_NOT_JSON(req_body);

                if (!v.is_object() &&
                    req->query_params.size() <= 0)   // body 不是 JSON 对象，且没有 query，报错
                    HTTP_NOT_JSON_OBJ(req_body);

                // 请求中的 query 部分，也加入到 json 中，统一处理
                // 注意1：当某一参数在 query 和 body 中同时指定时，query 的优先级更高
                // 注意2：query 中指定的参数，一律视为 std::string 类型，这里不做类型转换
                for (auto q : req->query_params)
                    if (!v.is_object())
                        v.emplace_object()[q.first] = q.second;
                    else
                        v.as_object()[q.first] = q.second;
            }

            result = f.func(f.params_def, v);
        } else {
            result = HTTP_404(method + " + " + uri);   // 没有找到合适的，返回 404
        }
    } catch (json_rep& x) {
        result = x;   // 返回 erc 对象给外部调用者
        result.reactivate();
    } catch (boost::system::system_error& er) {
        result = HTTP_FUNC_FAILED(er.what());   // boost system错误，通常是系统或功能调用失败
    } catch (const std::exception& e) {
        result = HTTP_OTHER_EXP(e.what());   // 其它通用的异常
    } catch (...) {
        result = HTTP_UNKNOWN_ERR;           // 未知异常
    }

    resp->SetHeader("Server", "Http Server");
    // 前面调用了 m_http_router->AllowCORS();
    // resp->SetHeader("Access-Control-Allow-Origin", "*");    // 解决跨域问题
    resp->SetHeader("Access-Control-Allow-Methods", "*");   // 解决跨域问题
    resp->content_type = APPLICATION_JSON;
    resp->body         = result.to_resp_body();

    on_response(result);   // 发送消息：生成响应数据
    result.deactivate();

    return 200;
}

void http_srv::ws_open(const WebSocketChannelPtr& channel, const HttpRequestPtr& req) {
    on_ws_open(req->Path().c_str(), channel->id());
    req;

    // 以下只是 演示功能 用
    // 正式的功能中，如果有需要向客户端发送通知消息的情况，这里根据 path，进行订阅
    // 在服务端记录好 channel、id 和订阅的 path 后，产生消息时向客户端发送消息

    // 每秒发送一个字符串，只是演示功能
    // printf("onopen: GET %s\n", req->Path().c_str());
    //// send(time) every 1s
    // hv::setInterval(1000, [channel](hv::TimerID id) {
    //     if (channel->isConnected()) {
    //         char       str[DATETIME_FMT_BUFLEN] = {0};
    //         datetime_t dt                       = datetime_now();
    //         datetime_fmt(&dt, str);
    //         channel->send(std::format("Time: {}, ID: {}", str, channel->id()));
    //     } else {
    //         hv::killTimer(id);
    //     }
    // });
}

void http_srv::ws_message(const WebSocketChannelPtr& channel, const std::string& msg) {
    on_ws_message(channel->id(), msg);

    msgpack::serializer sr_request(msg.data(), msg.size());

    // 调用的ID
    // 调用的方法名称
    uint32_t    call_id;
    std::string funcname;

    // 封装返回的数据
    msgpack::serializer::ptr rptr(nullptr);

    try {
        sr_request >> call_id;
        sr_request >> funcname;

        // 尝试调用名称指定的服务方法，并获得返回的 response
        rptr = std::make_shared<msgpack::serializer>();
        if (m_map_ws_funcs.find(funcname) != m_map_ws_funcs.end()) {
            // 调用服务方法
            m_map_ws_funcs[funcname](rptr.get(), sr_request);
        } else {
            response_t<std::string> r(static_cast<int>(rep_code::FUNC_NOT_SUPPORT),
                                      std::string("function not regist : " + funcname),
                                      nullptr);
            *rptr.get() << r;
        }
    } catch (error_args_count& er) {
        // 参数错误（或者甚至没有方法名）
        rptr = std::make_shared<msgpack::serializer>();
        response_t<std::string> r(
            static_cast<int>(rep_code::FUNC_PARAM_COUNT_WRONG), er.what(), nullptr);
        *rptr.get() << r;
    } catch (error_args_type& er) {
        // 参数类型错误（无法转换）
        rptr = std::make_shared<msgpack::serializer>();
        response_t<std::string> r(static_cast<int>(rep_code::FIELD_TYPE_ERR), er.what(), nullptr);
        *rptr.get() << r;
    } catch (...) {
        // 其它未知错误
        rptr = std::make_shared<msgpack::serializer>();
        response_t<std::string> r(
            static_cast<int>(rep_code::UNKNOWN_ERR), std::string("Unknown error!"), nullptr);
        *rptr.get() << r;
    }

    // 先发送 call id，再发送数据
    channel->send((char*)&call_id, sizeof(uint32_t), WS_OPCODE_BINARY, false);
    channel->send(rptr->data(), (int)rptr->size(), WS_OPCODE_BINARY, true);

    // 发送 WebSocket 响应消息
    on_ws_response(channel->id(), (int)rptr->size() + sizeof(uint32_t));
}

void http_srv::ws_close(const WebSocketChannelPtr& channel) {
    on_ws_close(channel->id());
}